-
-
Notifications
You must be signed in to change notification settings - Fork 197
Copy node_modules to platform on prepare (fix Node6/npm 3.x bug) #2152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
copy production node_modules as-is to the project's tns_modules
9397e32
to
77f86a3
Compare
6b8c084
to
ec9f70a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have two concerns with this PR:
- The
getProductionDependencies
method is too complex and needs to be broken up in small chunks, cleaned up, and possibly moved to a different class. - I do not see anything preventing pulling two versions of a package (think huge packages like Angular) to your app's
tns_modules
dir, if it has been requested by your app's dependencies. What should we do in that case?
// console.log(productionDependencies); | ||
|
||
// TODO: Pip3r4o - result is not used currently | ||
// let nodeModules = this.getChangedNodeModules(absoluteOutputPath, platform, lastModifiedTime).wait(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get rid of commented out code?
var deps: any = []; | ||
var seen: any = {}; | ||
|
||
var pJson = path.join(projectPath, "package.json"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, avoid weird abbreviations like pJson
. How about packageJsonPath
?
|
||
} | ||
// module is scoped | ||
else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} else {
var dep = addDependency(deps, name, scopedModulePath, 0); | ||
traverseModule(scopedModulePath, depth, dep); | ||
} | ||
else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} else {
return; | ||
} | ||
|
||
var dep = addDependency(deps, name, modulePath, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, please avoid abbreviations: dep
|
||
return filterUniqueDirectories(deps); | ||
|
||
function traverseChild(name: string, currentModulePath: string, depth: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those inner functions are very confusing and unreadable. Consider moving them to methods of this class or an entirely new class.
} | ||
} | ||
|
||
function traverseModule(modulePath: string, depth: number, currentDependency: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the difference when traversing a "child" and a "module". I think one of these functions needs a better name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also please add return type to the function
} | ||
} | ||
|
||
function filterUniqueDirectories(dependencies: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use a map keyed by the dependency directory here (simulating a set collection) instead of doing linear traversals all the time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted. I used a string map initially to check if the plugin's already present in the list, but that approach omitted corner cases where 2 plugins with different versions were present. I'll revisit it again
@hdeshev about |
let pJson = path.join(projectPath, "package.json"); | ||
let nodeModulesDir = path.join(projectPath, "node_modules"); | ||
|
||
let content = require(pJson); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would advise using $fs
as this will make the code more testable:
this.$fs.readJson(pJson).wait();
|
||
let content = require(pJson); | ||
|
||
Object.keys(content.dependencies).forEach((key) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if there's no dependencies section in the package.json, this code will fail. I would use lodash's _.each
:
_.keys(content.dependencies)
.forEach(key => {
....
});
} | ||
|
||
if (packageJsonContents.dependencies) { | ||
Object.keys(packageJsonContents.dependencies).forEach((key) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above - it's safer to use:
_.keys(packageJsonContent.dependencies).forEach(...
} | ||
} | ||
|
||
function addDependency(deps: any[], name: string, directory: string, depth: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function needs return type
} | ||
} | ||
|
||
function traverseModule(modulePath: string, depth: number, currentDependency: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also please add return type to the function
} | ||
|
||
function addDependency(deps: any[], name: string, directory: string, depth: number) { | ||
let dep: any = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use shorter syntax here:
let dep = {
name,
directory,
depth
};
function filterUniqueDirectories(dependencies: any) { | ||
let unique: any = []; | ||
let distinct: any = []; | ||
for (let i in dependencies) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get directly the dependency by using:
for (let dep of dependencies) {
if (distinct.indexOf(dep.directory) > -1) {
....
}
public copyModules(dependencies: IDictionary<ILocalDependencyData>, platform: string): void { | ||
_.each(dependencies, dependency => { | ||
public copyModules(dependencies: any[], platform: string): void { | ||
for (var entry in dependencies) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var -> let
_.each(dependencies, dependency => { | ||
public copyModules(dependencies: any[], platform: string): void { | ||
for (var entry in dependencies) { | ||
var dependency = dependencies[entry]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var -> let
|
||
shelljs.mkdir("-p", targetDir); | ||
shelljs.cp("-Rf", dependency.directory, targetDir); | ||
// console.log("Copied dependency: " + dependency.name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you remove the commented line or add it as log trace message:
this.$logger.trace(`Copied dependency: ${dependency.name}`);
b66b4a7
to
cbfd5b8
Compare
@hdeshev @rosen-vladimirov addressed concerns with style and readability |
return dependency; | ||
} | ||
|
||
private ensureModuleExists(modulePath: string): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rename this to moduleExists
. Nothing to ensure anyway.
// check if key appears in a scoped module dependency | ||
let isScoped = name.indexOf('@') === 0; | ||
|
||
if (!isScoped) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scoped/unscoped branches seem to be mostly the same code copied/pasted over. Can we eliminate the duplication in a shared method and pass the different paths as parameters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right! I seem to have missed it!
f4a99cd
to
1b80824
Compare
fix broken tests
1b80824
to
7b10417
Compare
…ns_modules (npm2 hacky fix)
👍 looks good, the sooner this is in master, the better |
A while ago, we had a logic to find out which node_modules should be processed. However it is not used anymore (removed in #2152 ). So remove the code - we do not need it anymore.
* Fix Android debugging When executing `tns debug android` for slow emulators/devices we have logic to wait several seconds until debugger is attached. However we've missed to `await` the `sleep` method and in fact we are not waiting at all. Add the missing await, which fixes the `tns debug android` command. * Remove unused code A while ago, we had a logic to find out which node_modules should be processed. However it is not used anymore (removed in #2152 ). So remove the code - we do not need it anymore. * Fix type
Changes in this PR will allow copying of all
production
(non-dev) node_modules into the platform'stns_modules
independent of whether they have been installed usingtns install
(npm 2.x) or npm install withnpm
version 3+.The proposed implementation however will iterate through the production modules' package.jsons on every build. Traversal of all package's production dependencies is also a bit slower than before. I'll look into a way to address only changes on subsequent builds, and potentially optimize traversals.
Issue #2149 and the respective PR will most likely address preparing of modules on each rebuild. Has yet to be verified.
There are currently 3 failing tests testing how and where npm_modules are copied into the platforms dir.
The changes have been tested with the Groceries app (master branch) with both
tns install
(npm 2), andnpm install
(npm 3)Addresses issues: #1989, #1845, #1740
Also invalidates PR #2136
Depends on changes in both runtimes: NativeScript/android#587, NativeScript/ios-jsc#673;
ping: @rosen-vladimirov @hdeshev @Plamen5kov @atanasovg